package cn.iocoder.yudao.module.fm.service.tunnel;

import cn.iocoder.yudao.module.fm.controller.admin.fileinfo.vo.FileInfoCreateReqVO;
import cn.iocoder.yudao.module.fm.controller.admin.fileinfo.vo.FileInfoRespVO;
import cn.iocoder.yudao.module.fm.controller.admin.fileinfourl.vo.FileInfoUrlBaseVO;
import cn.iocoder.yudao.module.fm.enums.FileInfoType;
import cn.iocoder.yudao.module.fm.service.QRCodeGenerator;
import cn.iocoder.yudao.module.fm.service.fileinfo.FileInfoService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.SneakyThrows;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.fm.controller.admin.tunnel.vo.*;
import cn.iocoder.yudao.module.fm.dal.dataobject.tunnel.TunnelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.fm.convert.tunnel.TunnelConvert;
import cn.iocoder.yudao.module.fm.dal.mysql.tunnel.TunnelMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.fm.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import org.springframework.web.multipart.MultipartFile;

/**
 * 隧道 Service 实现类
 *
 * @author 档案
 */
@Service
@Validated
public class TunnelServiceImpl implements TunnelService {

    @Resource
    private TunnelMapper tunnelMapper;
    @Resource
    private FileInfoService fileInfoService;
    @Resource
    private QRCodeGenerator qrCodeGenerator;


    @Override
    public Long createTunnel(TunnelCreateReqVO createReqVO) {
        // 插入
        TunnelDO tunnel = TunnelConvert.INSTANCE.convert(createReqVO);
        tunnelMapper.insert(tunnel);
        Long tunnelId = tunnel.getId();


        // 生成二维码
        String qrCodeUrl = qrCodeGenerator.get(FileInfoType.TUNNEL.getValue(), tunnelId);
        tunnel.setQrCode(qrCodeUrl);
        tunnelMapper.updateById(tunnel);


        // 档案信息保存
        fileInfoService.save(createReqVO.getFileList(),
                tunnelId,
                FileInfoType.TUNNEL.getValue()
        );

        // 返回
        return tunnelId;
    }

    @Override
    public void updateTunnel(TunnelUpdateReqVO updateReqVO) {
        // 校验存在
        validateTunnelExists(updateReqVO.getId());
        // 更新
        TunnelDO updateObj = TunnelConvert.INSTANCE.convert(updateReqVO);
        tunnelMapper.updateById(updateObj);

        // 档案信息保存
        fileInfoService.save(updateReqVO.getFileList(),
                updateReqVO.getId(),
                FileInfoType.TUNNEL.getValue()
        );
    }

    @Override
    public void deleteTunnel(Long id) {
        // 校验存在
        validateTunnelExists(id);
        // 删除
        tunnelMapper.deleteById(id);
    }

    private void validateTunnelExists(Long id) {
        if (tunnelMapper.selectById(id) == null) {
            throw exception(DATA_NOT_EXISTS);
        }
    }

    @Override
    public TunnelDO getTunnel(Long id) {
        return tunnelMapper.selectById(id);
    }

    @Override
    public List<TunnelDO> getTunnelList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return tunnelMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<TunnelDO> getTunnelPage(TunnelPageReqVO pageReqVO) {
        return tunnelMapper.selectPage(pageReqVO);
    }

    @Override
    public List<TunnelDO> getTunnelList(TunnelExportReqVO exportReqVO) {
        return tunnelMapper.selectList(exportReqVO);
    }


    @Override
    public void importExcel(MultipartFile file) {
        try {
            List<LinkedHashMap<Long, String>> readList = EasyExcel.read(file.getInputStream()).doReadAllSync();

            List<LinkedHashMap<Long, String>> masterList = readList.subList(0, 6);
            List<LinkedHashMap<Long, String>> children = readList.subList(7, readList.size());

            TunnelCreateReqVO tunnelCreateReqVO = new TunnelCreateReqVO();

            tunnelCreateReqVO.setNo(masterList.get(0).get(1));
            tunnelCreateReqVO.setMaterial(masterList.get(0).get(3));
            tunnelCreateReqVO.setSurroundingRockLithologyAndDepthOfBurial(masterList.get(0).get(5));

            tunnelCreateReqVO.setLength(masterList.get(1).get(1));
            tunnelCreateReqVO.setThicknessOfLining(masterList.get(1).get(3));
            tunnelCreateReqVO.setSecondLiningPouringTime(masterList.get(1).get(5));

            tunnelCreateReqVO.setFeatures(masterList.get(2).get(1));
            tunnelCreateReqVO.setDiseaseAndDisease(masterList.get(2).get(4));

            tunnelCreateReqVO.setLeaderOfTheStandTeam(masterList.get(3).get(1));
            tunnelCreateReqVO.setTeamLeaderOfConcreteClass(masterList.get(3).get(3));
            tunnelCreateReqVO.setGroupLeaderOfGroutingClassWithMold(masterList.get(3).get(5));

            tunnelCreateReqVO.setWetSprayManipulator(masterList.get(4).get(1));
            tunnelCreateReqVO.setLeaderOfDrainageTeam(masterList.get(4).get(3));
            tunnelCreateReqVO.setTechnician(masterList.get(4).get(5));

            tunnelCreateReqVO.setQualityInspector(masterList.get(5).get(1));
            tunnelCreateReqVO.setSurveyor(masterList.get(5).get(3));
            tunnelCreateReqVO.setEngineerOfSupervision(masterList.get(5).get(5));

            // 子表
            List<FileInfoCreateReqVO> fileInfoList = children.stream().map(map -> {
                FileInfoCreateReqVO fileInfoDO = new FileInfoCreateReqVO();
                fileInfoDO.setNo(map.get(0));
                fileInfoDO.setDocumentationStage(map.get(1));
                fileInfoDO.setFileName(map.get(2));
                fileInfoDO.setRemarks(map.get(4));
                fileInfoDO.setFileUrlList(Collections.emptyList());
                return fileInfoDO;
            }).collect(Collectors.toList());
            tunnelCreateReqVO.setFileList(fileInfoList);

            createTunnel(tunnelCreateReqVO);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("解析出错");
        }
    }

    @Override
    @SneakyThrows
    public ResponseEntity<byte[]> exportExcel(TunnelRespVO tunnelRespVO) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        ClassPathResource template = new ClassPathResource("template/tunnel-export-template.xlsx");

        try (ExcelWriter excelWriter = EasyExcelFactory.write(outputStream)
                .withTemplate(template.getInputStream())
                .build()) {

            // 创建 sheet
            WriteSheet writeSheet = EasyExcelFactory.writerSheet(0).build();

            // 渲染主表信息
            excelWriter.fill(tunnelRespVO, writeSheet);

            // 子表渲染
            List<FileInfoRespVO> fileList = tunnelRespVO.getFileList();
            for (FileInfoRespVO fileInfoRespVO : fileList) {
                fileInfoRespVO.setFileListExportString(fileInfoRespVO.getFileUrlList().stream().map(FileInfoUrlBaseVO::getUrl).collect(Collectors.joining("\n")));
            }

            excelWriter.fill(fileList, writeSheet);
            excelWriter.finish();

            byte[] byteArray = outputStream.toByteArray();
            String fileName = tunnelRespVO.getNo() + ".xlsx";

            HttpHeaders headers = new HttpHeaders();
            headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
            headers.add("Content-Disposition", "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);
            headers.add("Pragma", "no-cache");
            headers.add("Expires", "0");
            headers.add("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            return ResponseEntity.ok().headers(headers).body(byteArray);
        }
    }

}
